package com.heima.user.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.BehaviorConstants;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.LoginDto;
import com.heima.model.user.dtos.UserRelationDto;
import com.heima.model.user.pojos.ApUser;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.user.mapper.ApUserMapper;
import com.heima.user.service.ApUserService;
import com.heima.utils.common.AppJwtUtil;
import com.heima.utils.thread.WmThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements ApUserService {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public ResponseResult userFollow(UserRelationDto dto) {
        //1.校验
        if(dto==null || dto.getAuthorId()==null || dto.getOperation()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //关注作者也需要登陆
        // 前提条件是
        // 1.网关解析令牌得到用户id放入请求头然后路由到behavior微服务
        // 2.behaviro服务中要有拦截器  在前置拦截方法中获取请求头中的用户id  放入threadlocal，  拦截器需要生效
        WmUser user = WmThreadLocalUtil.getUser();
        if(user==null || user.getId()==0){// 没登陆  或者点了不登录先看看   都不允许点点赞按钮
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        //2.利用redis的set结构存储关注信息
        String authorId = dto.getAuthorId().toString();//被关注人   作者id
        String userId = user.getId().toString();//关注人   等当前登录人id

        //APUSER-FOLLOW-userId  当前登录人关注了谁
        BoundSetOperations<String, String> setFollowOps = stringRedisTemplate.boundSetOps(BehaviorConstants.APUSER_FOLLOW_RELATION + userId);

        //APUSER-FANS-authorId   被关注人粉丝有谁
        BoundSetOperations<String, String> setFansOps = stringRedisTemplate.boundSetOps(BehaviorConstants.APUSER_FANS_RELATION + authorId);

        if(dto.getOperation()==0){//关注
            Boolean member = setFollowOps.isMember(authorId);
            if(member!=null && member){
                //点关注时，之前已经关注过该作者
                return ResponseResult.errorResult(AppHttpCodeEnum.FOLLOW_EXISTS);
            }
            setFollowOps.add(authorId);//将作者id添加到我的关注列表中
            setFansOps.add(userId);//将当前登录人id 添加到 作者的粉丝列表中

        }else{//取消关注
            Boolean member = setFollowOps.isMember(authorId);
            if(member!=null && !member){
                //点关注时，之前已经关注过该作者
                return ResponseResult.errorResult(AppHttpCodeEnum.FOLLOW_NOT_EXISTS);
            }
            setFollowOps.remove(authorId);//将作者id从我的关注列表中移除
            setFansOps.remove(userId);//将当前登录人id  从 作者的粉丝列表中移除
        }

        //3.返回
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    public ResponseResult login(LoginDto dto) {
        //1.校验
        if(dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2正常登陆（手机号+密码）
        if(StringUtils.isNotBlank(dto.getPhone()) && StringUtils.isNotBlank(dto.getPassword())){
            //2.1根据手机号查询用户
            ApUser apUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, dto.getPhone()));
            //第一种做法是 先注册，登陆时校验用户信息是否存在，不存在不让登陆
            //第二种做法是  不用先注册，登录时，如果用户信息不存在，则自动注册用户信息
            if(apUser==null){
                return ResponseResult.errorResult(AppHttpCodeEnum.AP_USER_DATA_NOT_EXIST);
            }

            //校验用户的锁定状态
            if(apUser.getStatus()){
                return ResponseResult.errorResult(AppHttpCodeEnum.USER_STATUS_LOCK);
            }


            //2.2比对密码
            //用户输入的密码在前 盐值在后，  要和用户注册时密码生成方式保持一致   dto是封装前端参数的对象     apUser是数据库中数据封装的对象
            String tmpPassword = DigestUtils.md5DigestAsHex((dto.getPassword()+apUser.getSalt()).getBytes(StandardCharsets.UTF_8));
            if(!tmpPassword.equals(apUser.getPassword())){
                return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
            }

            //2.3生成jwt令牌返回
            String token = AppJwtUtil.getToken(Long.valueOf(apUser.getId()));
            Map<String,Object> map = new HashMap<>();
            apUser.setPassword(null);
            apUser.setSalt(null);
            map.put("user",apUser);
            map.put("token",token);
            return ResponseResult.okResult(map);

        }else{
            //3.不登录先看看(手机号和密码都为空) 生成jwt令牌返回
            String token = AppJwtUtil.getToken(0L);
            Map<String,Object> map = new HashMap<>();
            map.put("token",token);
            return ResponseResult.okResult(map);
        }
    }
}
